<?php

// Allow easy console colloring
require_once 'Console/Color.php';

/**
* Script for creating and loading database
*/
 
// Initialize the application path and autoloading


$dirname = $_SERVER['PWD'];

defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath($dirname . '/../www/application'));

set_include_path(implode(PATH_SEPARATOR, array(
    APPLICATION_PATH . '/../www/library',
    get_include_path(),
)));

require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
 
// Define some CLI options
$getopt = new Zend_Console_Getopt(array(
   'table|t=w' => 'Table name to create model file sout of',
   'env|e-s'   => 'Application environment for which to create model s(defaults to development)',
   'help|h'    => 'Help -- usage message',
));

try
{
    $getopt->parse();
}
catch (Zend_Console_Getopt_Exception $e)
{
    // Bad options passed: report usage
    echo $e->getUsageMessage();
    return false;
}
 
// If help requested, report usage message
if ($getopt->getOption('h'))
{
    echo $getopt->getUsageMessage();
    return true;
}
 
// Initialize values based on presence or absence of CLI options
$env      = $getopt->getOption('e');
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (null === $env) ? 'development' : $env);
 
$tableName = $getopt->getOption('t');

// Initialize Zend_Application
$pApplication = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
echo PHP_EOL . Console_Color::convert('%gUsing APPLICATION_ENV = ' . APPLICATION_ENV . '%n') . PHP_EOL . PHP_EOL;

// Try to include overrides.
if(is_file(APPLICATION_PATH . '/../../scripts/overrides.php'))
{
   require_once(APPLICATION_PATH . '/../../scripts/overrides.php');
}

// Initialize and retrieve DB resource
$bootstrap = $pApplication->getBootstrap();
$bootstrap->bootstrap('db');
$dbAdapter = $bootstrap->getResource('db');

$dbConfig = $dbAdapter->getConfig();
echo Console_Color::convert('%U%mProccess All Tables%n') . PHP_EOL . PHP_EOL;
try
{
   $sql = 'SHOW TABLES IN `' . $dbConfig['dbname'] . '`';
   //echo Console_Color::convert("%MSQL = %n") . Console_Color::convert('%m' . $sql .'%n') . PHP_EOL;
   $dbDesc = $dbAdapter->fetchAll($sql);
}
catch (Exception $e)
{
    echo Console_Color::convert('%rAN ERROR HAS OCCURED:%n') . PHP_EOL;
    echo $e->getMessage() . PHP_EOL;
    return false;
}

if($tableName !== null)
{
   return createModel($tableName);
}
else
{
   foreach($dbDesc as $key => $desc)
   {
      foreach($desc as $tableName)
      {
         $modelCreated = createModel($tableName);
      }
   }
}
// generally speaking, this script will be run from the command line
return true;

function createModel($tableName)
{
   global $dbAdapter;
   // this block executes the actual statements that were loaded from
   // the schema file.
   echo Console_Color::convert("%pProccessing table \"$tableName\"...%n") . PHP_EOL;
   try
   {
      $sql = 'SHOW columns FROM `' . $tableName . '`';
      //echo Console_Color::convert("%MSQL = %n") . Console_Color::convert('%m'.$sql.'%n') . PHP_EOL;
      $tableDesc = $dbAdapter->fetchAll($sql);
   }
   catch (Exception $e)
   {
       echo Console_Color::convert('%rAN ERROR HAS OCCURED:%n') . PHP_EOL;
       echo $e->getMessage() . PHP_EOL;
       return false;
   }

   // Create Camel Case strings out of feild names
   $largestFieldCount = 0;
   foreach($tableDesc as &$row)
   {
      $row["camelCase"]    = makeLowercamelcase($row["Field"]);
      $row["PascalCase"]   = ucfirst($row["camelCase"]);
      if(strlen($row["Field"]) > $largestFieldCount)
         $largestFieldCount = strlen($row["Field"]);
   }
   $strPad = '';
   for($i = 0; $i < $largestFieldCount+ ($largestFieldCount%3); $i++)
      $strPad .= ' ';

   $dbModelString = makeDbModelFileString($tableName, $tableDesc, $strPad);
   $modelString = makeModelFileString($tableName, $tableDesc, $strPad);
   $modelMapperString = makeModelMapperFileString($tableName, $tableDesc, $strPad);

   $dbModelFilePath = APPLICATION_PATH . '/models/DbTable/' . ucfirst(makeLowercamelcase($tableName))  . '.php';
   $modelFilePath = APPLICATION_PATH . '/models/' . ucfirst(makeLowercamelcase($tableName))  . '.php';
   $modelMapperFilePath = APPLICATION_PATH . '/models/' . ucfirst(makeLowercamelcase($tableName))  . 'Mapper.php';

   $newContent = switchOutContent($dbModelFilePath, $dbModelString, true);
   if(is_file($dbModelFilePath))
   {
      //echo Console_Color::convert("%y\tUpdated DbModel file.%n\n");
   }
   else
   {
      echo Console_Color::convert("%g\tCreated DbModel file.%n\n");
   }
   file_put_contents($dbModelFilePath, $newContent);

   $newContent = switchOutContent($modelFilePath, $modelString, true);
   if(is_file($dbModelFilePath))
   {
      //echo Console_Color::convert("%y\tUpdated Model file.%n\n");
   }
   else
   {
      echo Console_Color::convert("%g\tCreated Model file.%n\n");
   }
   file_put_contents($modelFilePath, $newContent);

   $newContent = switchOutContent($modelMapperFilePath, $modelMapperString);
   if(is_file($dbModelFilePath))
   {
      //echo Console_Color::convert("%y\tUpdated ModelMapper file.%n\n");
   }
   else
   {
      echo Console_Color::convert("%g\tCreated ModelMapper file.%n\n");
   }
   file_put_contents($modelMapperFilePath, $newContent);
   return true;
}

function switchOutContent($filePath, $fullString, $callParentCtor = false)
{
   $snipText = "//%%--SNIP--DO-NOT-REMOVE--SNIP--%%";
   $userContent = "";
   $newBlankContent = "$snipText\n\n   // User created mothods and members go in here \n\n";
   $newBlankContent .= "   // Constructor" . PHP_EOL;
   $newBlankContent .= '   public function __construct(array $options = null)' . PHP_EOL;
   $newBlankContent .= "   {" . PHP_EOL;
   if($callParentCtor)
      $newBlankContent .= '      parent::__construct($options);' . PHP_EOL;
   $newBlankContent .= "   }" . PHP_EOL;
   $newBlankContent .= "\n$snipText";
   if(file_exists($filePath))
   {
      $oldContent = file_get_contents($filePath);
      $firstSnip = strpos($oldContent, $snipText);
      $secondSnip = strpos($oldContent, $snipText, $firstSnip + strlen($snipText) + 1);
      if($firstSnip !== false && $secondSnip !== false)
      {
         $userContent = $snipText;
         $userContent .= substr($oldContent, $firstSnip + strlen($snipText) , $secondSnip - $firstSnip - strlen($snipText));
         $userContent .= $snipText;
      }
      else
      {
         $userContent = $newBlankContent;
      }
   }
   else
   {
      $userContent = $newBlankContent;
   }
   
   return str_replace("%%SNIPHERE%%", $userContent, $fullString);
   
}

function makeDbModelFileString($tableName, $tableDesc, $strPad)
{
   $extends = getOverride('EXTENDS', "DbTable_" . ucfirst(makeLowercamelcase($tableName)), 'Zend_Db_Table_Abstract');   

   $str  = '<?php' . PHP_EOL;
   $str .= generateCopyright() . PHP_EOL;
   $str .= "class Application_Model_DbTable_" .  ucfirst(makeLowercamelcase($tableName)) . ' extends ' . $extends . PHP_EOL;
   $str .= '{' . PHP_EOL;
   $str .= '   protected $_name = ' . "'$tableName';" . PHP_EOL;
   $str .= '%%SNIPHERE%%'. PHP_EOL;
   $str .= '}' . PHP_EOL;
   return $str;
}

function makeModelMapperFileString($tableName, $tableDesc, $strPad)
{
   global $defaultModelMapperExtends;
   $extends = getOverride('EXTENDS', ucfirst(makeLowercamelcase($tableName)) . 'Mapper', $defaultModelMapperExtends);
   $extendsReplaced = false;
   if($extends != $defaultModelMapperExtends)
      $extendsReplaced = true;
   
   $str  = '<?php' . PHP_EOL;
   $str .= generateCopyright() . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* Application_Model_' . ucfirst(makeLowercamelcase($tableName)) . 'Mapper                                          */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= "class Application_Model_" . ucfirst(makeLowercamelcase($tableName)) . "Mapper extends $extends" . PHP_EOL;
   $str .= '{' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* User Defined Functions                                                                         */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= '%%SNIPHERE%%'. PHP_EOL;
   $str .= PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* Helper Functions                                                                               */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= '   public function modelName()   { return "' . makeLowercamelcase($tableName) . '"; }' . PHP_EOL;
   $str .= PHP_EOL;
   
   $str .= PHP_EOL;
   $str .= '   protected function setRow($row, Application_Model_' . ucfirst(makeLowercamelcase($tableName))  . ' & $model)' . PHP_EOL;
   $str .= '   {' . PHP_EOL;
   foreach($tableDesc as &$row)
   {
      $str .= '      if(isset($row->' . $row["Field"] . ')) $model->set' . $row["PascalCase"] . '($row->' . $row["Field"] . ');' . PHP_EOL;
   }
   $str .= '      parent::setRow($row, $model);' . PHP_EOL;
   $str .= '   }' . PHP_EOL;
   $str .= PHP_EOL;

   $str .= PHP_EOL;
   $str .= '   public function getDataAsArray(Application_Model_' . ucfirst(makeLowercamelcase($tableName))  . ' & $model, $forPdo = false)' . PHP_EOL . '   {' . PHP_EOL;
   $str .= '      $data = array(' . PHP_EOL;
   foreach($tableDesc as &$row)
   {
      if($row['Key'] == "PRI" || $row['Default'] == "CURRENT_TIMESTAMP")
         continue;
      $str .= "         '" . $row["Field"]  . "'" . substr($strPad, strlen($row["Field"])) . " => " . '$model->get' . $row["PascalCase"] . '($forPdo),' . PHP_EOL;
   }
   $str .= '      );' . PHP_EOL . PHP_EOL;
   $str .= '      $this->postGetDataAsArray($data, $model);' . PHP_EOL;
   $str .= '      return $data;' . PHP_EOL;
   $str .= '   }' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* Parent Class Overrides                                                                         */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '   public function fetchById($id) '. PHP_EOL;
   $str .= '   {' . PHP_EOL;
   $str .= '      $p' . $tableName . ' = null;' . PHP_EOL;
   $str .= '      // Check to see if we should run this function'. PHP_EOL;
   $str .= '      if(!$this->localFetchById($id, $p' . $tableName . '))'. PHP_EOL;
   $str .= '         return $p' . $tableName . ';'. PHP_EOL;
   $str .= '      ' . PHP_EOL;
   $str .= '      $p' . $tableName . ' = $this->loadFromCache($this->getKeyNameById($id));' . PHP_EOL;
   $str .= '      // ' . $tableName . ' found in cache' . PHP_EOL;
   $str .= '      if($p' . $tableName . ')' . PHP_EOL;
   $str .= '         return $p' . $tableName . ';' . PHP_EOL;
   $str .= '      ' . PHP_EOL;
   $str .= '      // ' . $tableName . ' not found in cache, look it up in the database' . PHP_EOL;
   $str .= '      $p' . $tableName . ' = parent::fetchById($id);' . PHP_EOL;
   $str .= '      // Save the result in the cache so future lookup events will find it' . PHP_EOL;
   $str .= '      $this->saveToCache($p' . $tableName . ', $this->getKeyNameById($id));' . PHP_EOL;
   $str .= '      ' . PHP_EOL;
   $str .= '      return $p' . $tableName . ';' . PHP_EOL;
   $str .= '   }' . PHP_EOL;
   $str .= '}' . PHP_EOL;
   $str .= PHP_EOL;
   return $str;
}

function makeModelFileString($tableName, $tableDesc, $strPad)
{
   global $defaultModelExtends;
   $extends = getOverride('EXTENDS', ucfirst(makeLowercamelcase($tableName)), $defaultModelExtends);
   $modelPropsInit = '   public static $modelProps = array(';
   $modelProps = $modelPropsInit;
   
   $str  = '<?php' . PHP_EOL;
   $str .= generateCopyright() . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* Application_Model_' . ucfirst(makeLowercamelcase($tableName)) . '                                                */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= "class Application_Model_" . ucfirst(makeLowercamelcase($tableName)) . " extends $extends" . PHP_EOL;
   $str .= '{' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* Programmer Defined Functions                                                                   */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= '%%SNIPHERE%%'. PHP_EOL;
   $str .= PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* Member Variables                                                                               */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= PHP_EOL;
   foreach($tableDesc as &$row)
   {
      if($modelProps != $modelPropsInit)
         $modelProps .= ', ';
      $modelProps .= '\'' . $row["PascalCase"] . '\'';
      $str        .= '   protected $_' . $row["camelCase"]  . ';' . PHP_EOL;
   }
   $str .= PHP_EOL . $modelProps . ');' . PHP_EOL;
   $str .= '   protected static $allModelProps = null;' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* Helper Functions                                                                               */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= '   public function modelName()   { return "' . makeLowercamelcase($tableName) . '"; }' . PHP_EOL;
   $str .= PHP_EOL;
   
   $str .= PHP_EOL;
   $str .= '   public static function mapper()' . PHP_EOL;
   $str .= '   {' . PHP_EOL;
   $str .= '      return new Application_Model_' . ucfirst(makeLowercamelcase($tableName)) . 'Mapper();' . PHP_EOL;
   $str .= '   }' . PHP_EOL;
   $str .= PHP_EOL;
   $str .= '   public static function modelProps()' . PHP_EOL;
   $str .= '   {' . PHP_EOL;
   $str .= '      if(self::$allModelProps === null)' . PHP_EOL;
   $str .= '         self::$allModelProps = array_unique(array_merge(Application_Model_' . ucfirst(makeLowercamelcase($tableName)) . '::$modelProps, parent::modelProps()));' . PHP_EOL;
   $str .= '      return self::$allModelProps;' . PHP_EOL;
   $str .= '   }' . PHP_EOL;
   $str .= PHP_EOL;
   
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= '/* Getters, Setters, and ENUMs                                                                    */' . PHP_EOL;
   $str .= '/**************************************************************************************************/' . PHP_EOL;
   $str .= PHP_EOL;

   $postSets = getOverride('MODEL_POST_SETS', ucfirst(makeLowercamelcase($tableName)), array());
   $postGets = getOverride('MODEL_POST_GETS', ucfirst(makeLowercamelcase($tableName)), array());
   $setOverrides = getOverride('MODEL_SET_OVERRIDES', ucfirst(makeLowercamelcase($tableName)), array());
   $getOverrides = getOverride('MODEL_GET_OVERRIDES', ucfirst(makeLowercamelcase($tableName)), array());
   $jsonMemberOverrides = getOverride('MODEL_MEMBER_USES_JSON', ucfirst(makeLowercamelcase($tableName)), array());
   
   foreach($tableDesc as &$row)
   {
      $rhsAssignmentValue = '$rhs';
      $enumList = array();
      if(strpos($row['Type'], ' unsigned zerofill'))
      {
         // zero fill the number on set
         $leftParen = strpos($row['Type'], '(');
         $rightParen = strpos($row['Type'], ')');
         $fillSize = substr($row['Type'], $leftParen + 1, $rightParen - ($leftParen + 1));
         $rhsAssignmentValue = '$this->addZeroPadding(' . $fillSize . ', $rhs)';
      }
      else if(substr($row['Type'], 0, 4) == 'enum')
      {
         $listAsString = substr($row['Type'], 5, -1);
         $list = explode(",", $listAsString);
         foreach($list as $item)
         {
            // Remove the "'"
            $item = substr($item, 1, -1);
            $enumList[$item] = strtoupper($row["PascalCase"] . '__' . makeUnderscoreFromCamelcase($item));
         }
      }

      // ENUM VALUES
      $enumArrayVarName = '$s' . ucfirst($row["PascalCase"] . 'EnumArray');
      $enumArrayStr = 'public static ' . $enumArrayVarName . ' = array(';
      if(count($enumList) > 0)
         $str .= '   // ENUM values for ' . $row["PascalCase"] . PHP_EOL;
      foreach($enumList as $key => $value)
      {
         $str .= '   const ' . $value . ' = \'' . $key . '\';' . PHP_EOL;
         $enumArrayStr .= PHP_EOL . '      \'' . $value . '\'  => self::' .  $value;
         end($enumList);
         if(key($enumList) != $key)
            $enumArrayStr .= ',';
      }
      $enumArrayStr .= PHP_EOL . '   );';
      if(count($enumList) > 0)
         $str .= '   ' . $enumArrayStr . PHP_EOL . PHP_EOL;
      
      $str .= '   // Get/Set for ' . $row["PascalCase"] . PHP_EOL;
      // GET
      if(in_array($row["PascalCase"], $getOverrides))
      {
         $str .= '   // overrides directive: function "get' . $row["PascalCase"] . '" was not generated' . PHP_EOL;
      }
      else if(in_array($row["PascalCase"], $jsonMemberOverrides) && count($enumList) == 0)
      {
         $str .= '   protected $mDecoded' . $row["camelCase"] . ' = null;' . PHP_EOL;
         $str .= '   public function get' . $row["PascalCase"] . '($forPdo = false)' . PHP_EOL;
         $str .= '   {' . PHP_EOL;
         $str .= '      if($forPdo)' . PHP_EOL;
         $str .= '      {' . PHP_EOL;
         $str .= '         if($this->_' . $row["camelCase"] . ' === null && $this->mDecoded' . $row["camelCase"] . ' !== null)' . PHP_EOL;
         $str .= '            $this->_' . $row["camelCase"] . ' = json_encode($this->mDecoded' . $row["camelCase"] . ');' . PHP_EOL;
         $str .= '         return $this->_' . $row["camelCase"] . ';' . PHP_EOL;
         $str .= '      }' . PHP_EOL;
         $str .= '' . PHP_EOL;
         $str .= '      if($this->mDecoded' . $row["camelCase"] . ' === null && $this->_' . $row["camelCase"] . ' !== null)' . PHP_EOL;
         $str .= '         $this->mDecoded' . $row["camelCase"] . ' = json_decode($this->_' . $row["camelCase"] . ', true);' . PHP_EOL;
         $str .= '' . PHP_EOL;
         $str .= '      return $this->mDecoded' . $row["camelCase"] . ';' . PHP_EOL;
         $str .= '   }' . PHP_EOL;
      }
      else
      {
         $append = '';
         if(in_array($row["PascalCase"], $postGets))
            $append = '$this->_postGet' . $row["PascalCase"] . '()';
         $str .= '   public function get' . $row["PascalCase"] . '($forPdo = false)    ' . substr($strPad, strlen($row["PascalCase"])) . '{ return $this->_' . $row["camelCase"] .';  ' . $append . '}' . PHP_EOL;
      }
      
      // SET
      if(in_array($row["PascalCase"], $setOverrides))
      {
         $str .= '   // overrides directive: function "set' . $row["PascalCase"] . '" was not generated' . PHP_EOL;
      }
      else if(in_array($row["PascalCase"], $jsonMemberOverrides) && count($enumList) == 0)
      {
         $str .= '   public function set' . $row["PascalCase"] . '($rhs)' . PHP_EOL;
         $str .= '   {' . PHP_EOL;
         $str .= '      if($rhs === null)' . PHP_EOL;
         $str .= '      {' . PHP_EOL;
         $str .= '         $this->_' . $row["camelCase"] . ' = null;' . PHP_EOL;
         $str .= '         $this->mDecoded' . $row["camelCase"] . ' = null;' . PHP_EOL;
         $str .= '      }' . PHP_EOL;
         $str .= '      else if(is_array($rhs))' . PHP_EOL;
         $str .= '      {' . PHP_EOL;
         $str .= '         $this->_' . $row["camelCase"] . ' = null;' . PHP_EOL;
         $str .= '         $this->mDecoded' . $row["camelCase"] . ' = $rhs;' . PHP_EOL;
         $str .= '      }' . PHP_EOL;
         $str .= '      else' . PHP_EOL;
         $str .= '      {' . PHP_EOL;
         $str .= '         $this->_' . $row["camelCase"] . ' = $rhs;' . PHP_EOL;
         $str .= '         $this->mDecoded' . $row["camelCase"] . ' = null;' . PHP_EOL;
         $str .= '      }' . PHP_EOL;
         $str .= PHP_EOL;
         $str .= '      if($this->mChangeSetReady && $this->mDecoded' . $row["camelCase"] . ' !== $rhs)' . PHP_EOL;
         $str .= '         $this->mChangeSet["' . $row["camelCase"] . '"] = $rhs;' . PHP_EOL;
         $str .= '   }' . PHP_EOL;
      }
      else
      {
         $append = '';
         if(in_array($row["PascalCase"], $postSets))
            $append = '$this->_postSet' . $row["PascalCase"] . '()';
         $str .= '   public function set' . $row["PascalCase"] . '($rhs)               ' . substr($strPad, strlen($row["PascalCase"]));
         if(count($enumList) > 0)
            $str .= PHP_EOL . '   ';
         $str .= '{ ';
         if(count($enumList) > 0)
         {
            $str .= PHP_EOL . '      if($rhs != \'\' && !in_array($rhs, self::' . $enumArrayVarName . '))';
            $str .= PHP_EOL . '         throw(new Exception(\'The value "\' . ' . $rhsAssignmentValue . ' . \'" can not be assigned to ENUM value beacuse the ENUM does not define such a value.\'));';
            $str .= PHP_EOL . '      ';
         }
         $str .= 'if(' . $rhsAssignmentValue . ' === $this->_' . $row["camelCase"] . ') return; ';
         $str .= 'if($this->mChangeSetReady) $this->mChangeSet["' . $row["camelCase"] . '"] = $this->_' . $row["camelCase"] . '; ';
         $str .= '$this->_' . $row["camelCase"] .' = ' . $rhsAssignmentValue . '; ' . $append;
         if(count($enumList) > 0)
            $str .= PHP_EOL . '   ';
         $str .= '}' . PHP_EOL;
      }
      
      $str .= PHP_EOL;
   }
   $str .= '}' . PHP_EOL;
   return $str;
}

function makeLowercamelcase($str) 
{ 
   $str = str_replace('_', ' ', $str);
   return preg_replace("/\s+([a-z])/ie", 'strtoupper("$1")', trim($str)); 
}

function makeUnderscoreFromCamelcase($str)
{
   return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $str));
}

?>
